
#if defined(WIN32) || defined(WIN64)
#pragma unmanaged
#endif

#include <Liberty3D/Engine/Uuid.h>

#ifdef __APPLE__
#include <CoreFoundation/CoreFoundation.h>
#endif

#ifdef WIN32
#include <windows.h>
#include <Liberty3D/Engine/Conversion.h>
#endif

#include <string.h>

using namespace Liberty::Engine;

Uuid Uuid::create() {
#ifdef __APPLE__
    Uuid        uuid;
    CFUUIDRef   ref   = CFUUIDCreate(nullptr);
    CFUUIDBytes bytes = CFUUIDGetUUIDBytes(ref);
    
    memcpy(uuid.data, &bytes, sizeof(uuid.data));
    CFRelease(ref);
    return uuid;
#else
    Uuid uuid;

    CoCreateGuid((GUID*)uuid.data);
    return uuid;
#endif
}

Uuid::Uuid(const std::string& uuid) {
#ifdef __APPLE__
    CFStringRef sref  = CFStringCreateWithCString(nullptr, uuid.c_str(), kCFStringEncodingASCII);
    CFUUIDRef   ref   = CFUUIDCreateFromString(nullptr, sref);
    CFUUIDBytes bytes = CFUUIDGetUUIDBytes(ref);
    
    memcpy(data, &bytes, sizeof(data));
    CFRelease(ref);
    CFRelease(sref);
#else
    if (CLSIDFromString(UTF8_To_UTF16(uuid).c_str(), (LPCLSID)data) != NOERROR) {
        memset(data, 0, sizeof(data));
    }
#endif
}

Uuid::Uuid(const char* uuid) {
#ifdef __APPLE__
    CFStringRef sref  = CFStringCreateWithCStringNoCopy(nullptr, uuid, kCFStringEncodingASCII, nullptr);
    CFUUIDRef   ref   = CFUUIDCreateFromString(nullptr, sref);
    CFUUIDBytes bytes = CFUUIDGetUUIDBytes(ref);
    
    memcpy(data, &bytes, sizeof(data));
    CFRelease(ref);
    CFRelease(sref);
#else
    CLSIDFromString(UTF8_To_UTF16(uuid).c_str(), (LPCLSID)data);
#endif
}

std::string Uuid::toString() const {
#ifdef __APPLE__
    CFUUIDBytes bytes;
    
    memcpy(&bytes, &data, sizeof(data));

    CFUUIDRef   ref  = CFUUIDCreateFromUUIDBytes(nullptr, bytes);
    CFStringRef sref = CFUUIDCreateString(nullptr, ref);
    char        result[48];
    
    CFStringGetCString(sref, result, 48, kCFStringEncodingASCII);
    
    CFRelease(ref);
    CFRelease(sref);
    return result;
#else
    OLECHAR result[64];

    StringFromGUID2(*((GUID*)data), result, 64);
    return UTF16_To_UTF8(result);
#endif
}

size_t Uuid::hash() const {
    return data[0] ^ data[1] ^ data[2] ^ data[3];
}
